package db

import (
	"errors"
	"gitee.com/yysf-xin/dproxy/pkg/app"
	"gitee.com/yysf-xin/dproxy/pkg/model"
	"gitee.com/yysf-xin/dproxy/pkg/slog"
	"gitee.com/yysf-xin/dproxy/pkg/tools"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"reflect"
	"sync"
)

type Models struct {
	SshServer  *SshServer
	Tunnel     *Tunnel
	LocalHttp  *LocalServer
	RouteRule  *RouteRule
	Proxy      *Proxy
	TcpForward *TcpForward
	ProxyPass  *ProxyPass
	TurnClient *TurnClient
	TurnGroup  *TurnGroup
	SysConfig  *model.SysConfig
	CornConfig *model.CornConfig
	DictType   *model.DictType
	Dict       *model.Dict
	LogService *slog.Service
}
type Client struct {
	Db     *gorm.DB
	Models Models
	Cipher *tools.AesCipher
	Mux    sync.Mutex
}

func (c *Client) String() string {
	return "DB"
}

type CipherPlugin struct {
	*tools.AesCipher
}

func (c *CipherPlugin) Name() string {
	return "cipher"
}

func (c *CipherPlugin) Initialize(db *gorm.DB) error {
	return nil
}

func NewClient(cfg *app.DbConfig) (c *Client, err error) {
	c = &Client{}

	if cfg.DbName == "" {
		cfg.DbName = "dproxy.db"
		cfg.Upgrade = true
	}

	tools.Log.Println("open", cfg.DbName)
	db := OpenDB(cfg)
	if db == nil {
		return nil, errors.New("not support db name " + cfg.DbName)
	}

	// gorm:gorm@tcp(127.0.0.1:3306)/gorm?charset=utf8&parseTime=True&loc=muxMap

	c.Db, err = gorm.Open(db, &gorm.Config{
		Logger: logger.Default.LogMode(logger.LogLevel(cfg.LogLevel)),
	})

	if err != nil {
		tools.Log.Println(err)
	} else {
		c.Cipher, err = tools.NewAesCipher("&Sfxi5PXIBd*!wa2")
		if c.Cipher != nil && c.Db != nil {
			err = c.Db.Use(&CipherPlugin{
				c.Cipher,
			})
		}
		if db.Name() == "sqlite" {
			phyDb, _ := c.Db.DB()
			phyDb.SetMaxOpenConns(1)
		}
	}
	return
}

func UpgradeDB(models interface{}, db *gorm.DB) (err error) {
	var values = reflect.ValueOf(models).Elem()
	typeArr := make([]interface{}, values.NumField())
	for i := 0; i < values.NumField(); i++ {
		typeArr[i] = values.Field(i).Interface()
	}
	tools.Log.Println("start upgrade db..")
	err = db.AutoMigrate(typeArr...)
	return
}
